#include "pipelistener.h"
#include "glwidget.h"
#include <map>
#include <string>
#include <iostream>

using namespace std;

#define FIFO_FILE       "/tmp/CG_PIPE"
#define CMD_IDX 5

const char* CMDs[CMD_IDX] = {"AddCube","SetCubeLoc","AddLine","AddEdge","SetCubeColor"};
//enum E_CMDs = {e_ADDCUBE=0,e_UPDATECUBE};

vector<C_CLB_3D> V_CLBs;
vector<s_line> V_LINEs;

int fd;
FILE* fp;
char readbuf[128];
int COUNT = 0;
string strBUF;
string strEnd = ";";
string strArgDel = ",";

bool _get_arg(string& inStr,string& retArg);
bool _get_cmd(string& inStr,string& retCmd);
int _get_clb_idx(const char* clbName);
//void _get_arg_3floats(string str,float& f0,float& f1,float& f2);


int init_pipe (void) {
    //umask(0);
    //mknod(FIFO_FILE, S_IFIFO|0666, 0);
    umask(0);
    mkfifo(FIFO_FILE, 0666);
    
    fd = open(FIFO_FILE, O_RDONLY | O_NONBLOCK);
    //fd = open(FIFO_FILE, O_RDONLY);
    //fp = fopen(FIFO_FILE, "r");
    //memset(readbuf, 0, sizeof(readbuf));
}

int add_cube (vector<string>& args) {
    
    float x,y,z;
    float r,g,b;
    
    if (args.size()>4) {
        r = (float)atof(args[4].data());
        g = (float)atof(args[5].data());
        b = (float)atof(args[6].data());
    }

    x = (float)atof(args[1].data());
    y = (float)atof(args[2].data());
    z = (float)atof(args[3].data());
    
    C_CLB_3D NEWCLB(args[0].data(),x,y,z);

    if (args.size()>4)
        NEWCLB.setColor(r,g,b);

    printf("add_cube %s %f %f %f\n",args[0].data(),x,y,z);
    V_CLBs.push_back(NEWCLB);
    
    return 1;
}

int set_cube_loc (vector<string>& args) {
    
    int idx = _get_clb_idx(args[0].data());

    if (idx == -1)
        return 0;

    float x,y,z;
    
    x = (float)atof(args[1].data());
    y = (float)atof(args[2].data());
    z = (float)atof(args[3].data());

    V_CLBs[idx].set_loc(x,y,z);

    return 1;
}

int set_cube_color (vector<string>& args) {
    
    int idx = _get_clb_idx(args[0].data());

    if (idx == -1)
        return 0;

    float r,g,b;
    
    r = (float)atof(args[1].data());
    g = (float)atof(args[2].data());
    b = (float)atof(args[3].data());

    V_CLBs[idx].setColor(r,g,b);

    return 1;
}


int update_cube (vector<string>& args) {

    //if (M_CLBs.find(arg[0] != map::end)

    return 1;
}

// add_edge driver load
int add_edge (vector<string>& args) {
    
    if (args.size() != 2)
        return 0;

    int driver = -1, load = -1;

    driver = _get_clb_idx(args[0].data());
    load = _get_clb_idx(args[1].data());

    printf("add_edge %s %d %s %d\n",args[0].data(),driver,args[1].data(),load);

    if ((driver != -1) && (load != -1)) {
        V_CLBs[driver].addFanout(load);
        return 1;
    } else {

        if (driver == -1)
            printf ("ERROR: can not find driver %s\n",args[0].data());
        if (load == -1)
            printf ("ERROR: can not find load %s\n",args[1].data());
    }
    return 0;
}

// add_line x0,y0,z0,x1,y1,z1
int add_line (vector<string>& args) {
    
    float x0,y0,z0;
    float x1,y1,z1;
    s_line newline;

    if (args.size()>6) {
        newline.r = (float)atof(args[6].data());
        newline.g = (float)atof(args[7].data());
        newline.b = (float)atof(args[8].data());
    } else {
        newline.r = 1.0;
        newline.g = 1.0;
        newline.b = 0.0;   
    }

    newline.x0 = (float)atof(args[0].data());
    newline.y0 = (float)atof(args[1].data());
    newline.z0 = (float)atof(args[2].data());

    newline.x1 = (float)atof(args[3].data());
    newline.y1 = (float)atof(args[4].data());
    newline.z1 = (float)atof(args[5].data());

    V_LINEs.push_back(newline);
}

int update_annotate () {
    
}

int parse_cmds(void) {
    
    //strBUF.clear();
    memset(readbuf, 0, sizeof(readbuf));

    if (read(fd,readbuf,128)<1)
        return 0;

    printf("%s %d\n",readbuf,COUNT);
    COUNT++;
    //return 1;
    
    string cmd;
    string arg;
    bool isCmdFound = false;
    int cmdIdx;
    vector<string> args;

    strBUF.assign(readbuf);
    
    if(_get_cmd(strBUF,cmd) == false) {
        return 0;
    } else {

        printf("%s\n",strBUF.data());

        args.clear();

        // check if the command is legal or not
        for (int i=0;i<CMD_IDX;i++) {
            if ( cmd.compare(CMDs[i]) == 0 ) {
                isCmdFound = true;
                cmdIdx = i;
            }
        }

        if (isCmdFound == false) {
            printf("ERROR: uknown command stream...\n");
            printf("%s\n",cmd.data());
            exit(1);
        }

        // get arg
        while ( _get_arg(strBUF,arg) != false ) {
            printf("push %s\n",arg.data());
            args.push_back(arg);
        }
            
        // launch cmds
        printf("cmdIdx=%d\n",cmdIdx);
        switch (cmdIdx) {

            case 0: //add cube
                add_cube(args);
                break;
            case 1: //set cube loc
                set_cube_loc(args);
                break;
            case 2: //add line
                add_line(args);
                break;
            case 3:
                add_edge(args);
                break;
            case 4:
                set_cube_color(args);
                break;
            default:
                printf("ERROR: can not find command %s\n",cmd.data());
                break;
        }

    }
}

int close_pipe (void) {
    close(fd);
}

//////////////////////////////////////////////

bool _get_arg(string& inStr,string& retArg) {
    
    size_t pos;
    string token;

    size_t end = inStr.find(";");

    if (end == 0) { // start with ";"
        inStr.erase(0,end+1);
        return false;
    }

    printf("  arg before: %s\n",inStr.data());
    if ( (pos = inStr.find(",")) != string::npos &&
        (pos < end) ) {
        retArg = inStr.substr(0,pos);
        inStr.erase(0,pos+1);

        printf("  arg after: %s\n",inStr.data());
        return true;

    } else if ( (pos = inStr.find(")")) != string::npos ) {

        retArg = inStr.substr(0,pos);
        inStr.erase(0,pos+1);

        printf("  arg after: %s\n",inStr.data());
        return true;
    }
    return false;
}

bool _get_cmd(string& inStr,string& retCmd) {

    size_t pos;

    //printf("before: %s\n",inStr.data());
    if ( (pos = inStr.find("(")) != string::npos) {
        retCmd = inStr.substr(0,pos);
        inStr.erase(0,pos+1);

        printf("after: %s\n",inStr.data());
        return true;
    } else
        return false; // Can not find command
}

int _get_clb_idx(const char* clbName) {
    
    int idx = -1;
    string strTmp;
    strTmp.assign(clbName);

    for (unsigned int i=0;i<V_CLBs.size();i++) {
        
        if (strTmp.compare(V_CLBs[i].getName()) == 0)
            idx = i;

    }
    return idx;
}
